/**
 * Copyright 2019 Huawei Technologies Co.,Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use
 * this file except in compliance with the License.  You may obtain a copy of the
 * License at
 * <p>
 * http://www.apache.org/licenses/LICENSE-2.0
 * <p>
 * Unless required by applicable law or agreed to in writing, software distributed
 * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
 * CONDITIONS OF ANY KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations under the License.
 */
package obs;

import com.google.gson.Gson;
import com.obs.services.ObsClient;
import com.obs.services.ObsConfiguration;
import com.obs.services.exception.ObsException;
import com.obs.services.model.*;

import java.io.*;
import java.nio.ByteBuffer;
import java.nio.channels.Channels;
import java.nio.channels.ReadableByteChannel;
import java.nio.channels.WritableByteChannel;
import java.text.ParseException;
import java.text.SimpleDateFormat;

/**
 * 下载对象
 * 演示: 如何使用Java OBS SDK以不同方式从OBS下载对象
 */
public class DownloadSample {
    private static final String endPoint = "http://obs.cn-north-4.myhuaweicloud.com";
    private static final String ak = "NNNNWPW2FZHMYPRB3M79OBXXX";
    private static final String sk = "7ZRRRRX0kNN0SgsxtIsB6EBZGygWvpC04mezuT0pbBBBPu";
    private static ObsClient obsClient;
    private static String bucketName = "wuzheng-demo";
    private static String objectKey = "my-obs-object-key-demo";
    private static String localFilePath = "/temp/" + objectKey;

    //初始化obs配置
    static {
        ObsConfiguration config = new ObsConfiguration();
        config.setSocketTimeout(30000);
        config.setConnectionTimeout(10000);
        config.setEndPoint(endPoint);
        obsClient = new ObsClient(ak, sk, config);
    }

    public static void main(String[] args) throws IOException {
        try {
            //下载文件并保存到本地
            //downloadSimpleAndToLocal();
            //流式下载
            //downloadByStream();
            //按照范围下载
            //downloadRange();
            //获取下载进度
            //getProgress();
            //限定条件下载 如果对象的修改时间晚于该参数值指定的时间，则返回对象内容，否则抛出异常。
            //downloadLimit();
            //重写响应头
            //downloadOverwriteResponseHeader();
            // 获取自定义元数据
            //downloadWithMetaData();
            //断点续传
            //downloadByCheckPoint();
            //图片处理
            downloadImageDealWith("my-obs-object-key-demo");


        } catch (ObsException e) {
            System.out.println("Response Code: " + e.getResponseCode());
            System.out.println("Error Message: " + e.getErrorMessage());
            System.out.println("Error Code:       " + e.getErrorCode());
            System.out.println("Request ID:      " + e.getErrorRequestId());
            System.out.println("Host ID:           " + e.getErrorHostId());
        } finally {
            if (obsClient != null) {
                try {
                    /*
                     * Close obs client
                     */
                    obsClient.close();
                } catch (IOException e) {
                }
            }
        }
    }

    public static void downloadImageDealWith(String objectKey) throws IOException {
        GetObjectRequest request = new GetObjectRequest(bucketName, objectKey);
        // 对图片依次进行缩放、旋转
        request.setImageProcess("image/resize,m_fixed,w_100,h_100/rotate,90");
        ObsObject obsObject = obsClient.getObject(request);

        obsObject.getObjectContent().close();
    }

    //断点续传
    private static void downloadByCheckPoint() {
        DownloadFileRequest request = new DownloadFileRequest(bucketName, objectKey);
        // 设置下载对象的本地文件路径
        request.setDownloadFile("C:\\Users\\hufanglei\\Pictures");
        // 设置分段下载时的最大并发数
        request.setTaskNum(5);
        // 设置分段大小为10MB
        request.setPartSize(10 * 1024 * 1024);
        // 开启断点续传模式
        request.setEnableCheckpoint(true);
        try {
            // 进行断点续传下载
            DownloadFileResult result = obsClient.downloadFile(request);
            System.out.println(new Gson().toJson(result));
        } catch (ObsException e) {
            // 发生异常时可再次调用断点续传下载接口进行重新下载
        }
    }

    //设置自定义元数据
    private static void downloadWithMetaData() throws IOException {
        // 上传对象，设置自定义元数据
        PutObjectRequest request = new PutObjectRequest(bucketName, objectKey);
        ObjectMetadata metadata = new ObjectMetadata();
        metadata.addUserMetadata("property", "property-value");
        request.setMetadata(metadata);
        obsClient.putObject(request);

        // 下载对象，获取对象自定义元数据
        ObsObject obsObject = obsClient.getObject(bucketName, objectKey);
        System.out.println(obsObject.getMetadata().getUserMetadata("property"));
        obsObject.getObjectContent().close();
    }

    private static void downloadOverwriteResponseHeader() throws IOException {
        GetObjectRequest request = new GetObjectRequest(bucketName, objectKey);
        ObjectRepleaceMetadata replaceMetadata = new ObjectRepleaceMetadata();
        replaceMetadata.setContentType("image/jpeg");
        request.setReplaceMetadata(replaceMetadata);

        ObsObject obsObject = obsClient.getObject(request);
        System.out.println(obsObject.getMetadata().getContentType());

        obsObject.getObjectContent().close();
    }

    //不重要: 限定条件下载 如果对象的修改时间晚于该参数值指定的时间，则返回对象内容，否则抛出异常。
    private static void downloadLimit() throws ParseException, IOException {
        GetObjectRequest request = new GetObjectRequest(bucketName, objectKey);
        request.setRangeStart(0L);
        request.setRangeEnd(1000L);

        request.setIfModifiedSince(new SimpleDateFormat("yyyy-MM-dd").parse("2020-05-26"));
        ObsObject obsObject = obsClient.getObject(request);

        obsObject.getObjectContent().close();
    }

    private static void getProgress() throws IOException {
        GetObjectRequest request = new GetObjectRequest(bucketName, objectKey);
        request.setProgressListener(new ProgressListener() {
            @Override
            public void progressChanged(ProgressStatus status) {
                // 获取下载平均速率
                System.out.println("AverageSpeed:" + status.getAverageSpeed());
                // 获取下载进度百分比
                System.out.println("TransferPercentage:" + status.getTransferPercentage());
            }
        });
        //每上传1MB数据反馈下载进度
        request.setProgressInterval(1024 * 1024L);
        ObsObject obsObject = obsClient.getObject(request);
        // 读取对象内容
        System.out.println("Object content:");
        InputStream input = obsObject.getObjectContent();
        byte[] b = new byte[1024];
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        int len;
        while ((len = input.read(b)) != -1) {
            bos.write(b, 0, len);
        }
        System.out.println(new String(bos.toByteArray()));
        bos.close();
        input.close();
    }

    //按照范围下载
    public static void downloadRange() throws IOException {
        GetObjectRequest request = new GetObjectRequest(bucketName, objectKey);
        // 指定开始和结束范围
        request.setRangeStart(0L);
        request.setRangeEnd(1000L);
        ObsObject obsObject = obsClient.getObject(request);

        // 读取数据
        byte[] buf = new byte[1024];
        InputStream in = obsObject.getObjectContent();
        for (int n = 0; n != -1; ) {
            n = in.read(buf, 0, buf.length);
        }

        in.close();
    }

    //文本 流式下载
    public static void downloadByStream() throws IOException {

        System.out.println("Uploading a new object to OBS from a file\n");
        obsClient.putObject(bucketName, objectKey, createSampleFile());

        System.out.println("Downloading an object\n");

        ObsObject obsObject = obsClient.getObject(bucketName, objectKey);
        // 读取对象内容
        System.out.println("Object content:");
        InputStream input = obsObject.getObjectContent();
        byte[] b = new byte[1024];
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        int len;
        while ((len = input.read(b)) != -1) {
            bos.write(b, 0, len);
        }
        System.out.println(new String(bos.toByteArray()));
        bos.close();
        input.close();
    }

    //下载文件并保存到本地
    public static void downloadSimpleAndToLocal() throws IOException {
        /*
         * 将对象上传到您的存储桶
         */
        System.out.println("Uploading a new object to OBS from a file\n");
        obsClient.putObject(bucketName, objectKey, createSampleFile());

        System.out.println("Downloading an object\n");


        //将对象下载为输入流并直接显示
        simpleDownload();

        File localFile = new File(localFilePath);
        if (!localFile.getParentFile().exists()) {
            localFile.getParentFile().mkdirs();
        }

        System.out.println("Downloading an object to file:" + localFilePath + "\n");
        /*
         * Download the object to a file
         */
        downloadToLocalFile();

        System.out.println("Deleting object  " + objectKey + "\n");
        obsClient.deleteObject(bucketName, objectKey, null);
    }

    private static void downloadToLocalFile()
            throws ObsException, IOException {
        ObsObject obsObject = obsClient.getObject(bucketName, objectKey, null);
        ReadableByteChannel rchannel = Channels.newChannel(obsObject.getObjectContent());

        ByteBuffer buffer = ByteBuffer.allocate(4096);
        WritableByteChannel wchannel = Channels.newChannel(new FileOutputStream(new File(localFilePath)));

        while (rchannel.read(buffer) != -1) {
            buffer.flip();
            wchannel.write(buffer);
            buffer.clear();
        }
        rchannel.close();
        wchannel.close();
    }

    private static void simpleDownload()
            throws ObsException, IOException {
        ObsObject obsObject = obsClient.getObject(bucketName, objectKey, null);
        displayTextInputStream(obsObject.getObjectContent());
    }

    private static void displayTextInputStream(InputStream input) throws IOException {
        BufferedReader reader = new BufferedReader(new InputStreamReader(input));
        while (true) {
            String line = reader.readLine();
            if (line == null) {
                break;
            }
            System.out.println("\t" + line);
        }
        System.out.println();

        reader.close();
    }

    private static File createSampleFile() throws IOException {
        File file = File.createTempFile("obs-java-sdk-", ".txt");
        file.deleteOnExit();
        Writer writer = new OutputStreamWriter(new FileOutputStream(file));
        writer.write("abcdefghijklmnopqrstuvwxyz\n");
        writer.write("0123456789011234567890\n");
        writer.close();

        return file;
    }

}
